import numpy
import numpy as np
import cv2
import os
from tkinter import *
import tkinter.messagebox
from shutil import copy
from PIL import Image, ImageDraw, ImageFont


def createImg(width, height, R, G, B):
    '''
    创建任意大小图片矩阵
    :param width: 创建图片的宽度
    :param height:创建图片的高度
    :param R:颜色R
    :param G:颜色G
    :param B:颜色B
    :return:三通道图片数组
    '''
    creat_img3 = np.zeros([height, width, 3], np.uint8)  # 高height*宽width*通道3 单通道8位
    creat_img3[:, :, 0] = np.ones([height, width]) * B  # 0(Blue)通道全部赋值B
    creat_img3[:, :, 1] = np.ones([height, width]) * G  # 1(Green)通道全部赋值G
    creat_img3[:, :, 2] = np.ones([height, width]) * R  # 2(Red)通道全部赋值R
    return creat_img3


def addImg(objectImg, backgroundImg, startX, startY):
    '''
    将一张图片覆盖到另一张的某个区域
    :param objectImg: 上层图片
    :param backgroundImg: 背景图片
    :param startX: 起始X坐标
    :param startY: 起始Y坐标
    :return: 叠加完成后的背景图
    '''
    bgHeight, bgWidth, bgColorT = backgroundImg.shape
    obHeight, obWidth, obColorT = objectImg.shape
    width = height = 0
    if (obWidth + startX > bgWidth):
        width = bgWidth - startX
    else:
        width = obWidth + startX

    if (obHeight + startY > bgHeight):
        height = bgHeight - startY
    else:
        height = obHeight + startY

    backgroundImg[int(startY):int(height), int(startX):int(width)] = objectImg[0:int((height - startY)),
                                                                     0:(int(width - startX))]
    return backgroundImg


def ms2time(ms, type):
    '''
    毫秒数/秒数 转 时间
    :param ms: 毫秒数或者秒数
    :param type: 为s认为传入为秒数，为ms则认为传入的时毫秒数
    :return: 字符串类型的时间
    '''
    if (type == "s"):
        s = ms
    elif (type == "ms"):
        s = ms / 1000
    else:
        s = ms / 1000
    hours = int(s / (60 * 60))
    s -= (hours * 60 * 60)
    minute = int(s / 60)
    s -= minute * 60
    second = int(s)
    return str(hours) + ':' + str(minute) + ':' + str(second)


def getFileName(filepath):
    '''
    由文件路径获取文件名
    :param filepath: 文件路径（含文件名）
    :return: 文件名
    '''
    sp_res = filepath.split('\\');
    return sp_res[-1]


def getFilePath(filepath):
    '''
    从文件路径中获取路径部分（不带文件名）
    :param filepath: 文件路径（带文件名）
    :return:
    '''
    sp_res = filepath.split('\\');
    filepath_list = sp_res[0:len(sp_res) - 1]
    path = ""
    for sp_str in filepath_list:
        path += (sp_str + '\\')
    return path


def cv2ImgAddText(img, text, left, top, textColor=(0, 255, 0), textSize=20):
    '''
    向CV2的图片中添加文字（因为原生的2添加方法不支持中文）
    :param img:底图
    :param text:被添加的文件
    :param left:左上角X坐标
    :param top:左上角Y坐标
    :param textColor:文本颜色
    :param textSize:文字大小
    :return:
    '''
    if (isinstance(img, numpy.ndarray)):  # 判断是否OpenCV图片类型
        img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    draw = ImageDraw.Draw(img)
    fontText = ImageFont.truetype(
        "msyh.ttf", textSize, encoding="utf-8")
    draw.text((left, top), text, textColor, font=fontText)
    return cv2.cvtColor(numpy.asarray(img), cv2.COLOR_RGB2BGR)


def buildVideInfoImg(filepath):
    '''
    生成方法（生成一个视频的预览图）
    :param filepath: 视频文件路径
    :return:
    '''
    # 打开视频文件
    video = cv2.VideoCapture(filepath)
    # 获取视频宽度
    width = video.get(cv2.CAP_PROP_FRAME_WIDTH)
    # 获取视频高度
    height = video.get(cv2.CAP_PROP_FRAME_HEIGHT)
    # 获取视频总帧数
    all_count = video.get(cv2.CAP_PROP_FRAME_COUNT)
    # 获取视频码率
    fps = video.get(cv2.CAP_PROP_FPS)
    # 获取视频文件的文件名
    filename = getFileName(filepath)
    # 获取文件路径
    path = getFilePath(filepath)
    # 每一幅预览图的空隙（像素）
    space_width = 30
    # 信息显示栏高度（像素）
    info_height = 500
    # 截取预览图总帧数百分比位置
    cut_point_list = [0.01, 0.05, 0.08, 0.15, 0.22, 0.29, 0.36, 0.43, 0.50, 0.57, 0.64, 0.71, 0.78, 0.85, 0.92, 0.99]
    # 创建背景图
    backgroundImg = createImg(int(width * 4 + space_width * 3), int(height * 4 + space_width * 3 + info_height), 255,
                              255, 255)
    # 循环向背景图上叠加预览图
    start = 0
    for Y in range(0, 4):
        for X in range(0, 4):
            # 根据截图百分比列表定位视频
            point_count = cut_point_list[start] * all_count
            video.set(cv2.CAP_PROP_POS_FRAMES, point_count)
            # 获取这一帧画面
            ret, cut_image = video.read()
            # 获取这一帧所在时间（毫秒数）
            now_time = video.get(cv2.CAP_PROP_POS_MSEC)
            # 将时间写在预览图上
            cut_image = cv2ImgAddText(cut_image, ms2time(now_time, "ms"), 0, (height - 100), (225, 0, 225), 80)
            if ret:
                # 计算图片位置
                startX = width * X + space_width * X
                startY = height * Y + space_width * Y + info_height
                print(start)
                # 将预览图叠加在背景图上
                backgroundImg = addImg(cut_image, backgroundImg, startX, startY)
            start = start + 1
    # 输出视频信息
    backgroundImg = cv2ImgAddText(backgroundImg, filename, 0, 15, (0, 0, 0), 100)
    backgroundImg = cv2ImgAddText(backgroundImg, "FPS:" + str(fps), 0, 180, (0, 0, 0), 60)
    backgroundImg = cv2ImgAddText(backgroundImg, str(int(height)) + "X" + str(int(width)), 0, 260, (0, 0, 0), 60)
    backgroundImg = cv2ImgAddText(backgroundImg, "Time:" + ms2time(all_count / fps, "s"), 0, 340, (0, 0, 0), 60)
    # 输出程序信息
    backgroundImg = cv2ImgAddText(backgroundImg, "VideoInfoImgBuilder by NC 2020-1-19", 0, 420, (0, 0, 0), 60)
    # 创建预览图片
    cv2.imwrite('videoInfo.jpg', backgroundImg)
    video.release()  # 关闭相机
    # 移动文件
    copy('videoInfo.jpg', path + 'videoInfo.jpg')
    os.remove('videoInfo.jpg')


# 测试-调用
# buildVideInfoImg("")


windows = Tk()
windows.title("VideoInfoImgBuilder By NC 2020-1-19")
windows.geometry("400x60")

pathInput = Entry(windows, show=None)
pathInput.place(x=0, y=0, width=350, height=30, anchor=NW)

ouputLable = Label(windows, text="输入视频文件路径，点击生成按钮生成预览图片")
ouputLable.place(x=0, y=30, width=400, height=30, anchor=NW)

def startBuilder():
    path = pathInput.get()
    buildVideInfoImg(path)


startBtn = Button(windows, text="生成", command=startBuilder)
startBtn.place(x=350, y=0, width=50, height=30, anchor=NW)

# 进入消息循环
windows.mainloop()
